package top.someapp.dxf2dsvg.jfx;

import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.JSVGScrollPane;
import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import top.someapp.dxf2dsvg.CadImageExporter;
import top.someapp.dxf2dsvg.base.ExportOptions;
import top.someapp.dxf2dsvg.kits.Urls;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author zwz
 * Created on 2020-04-24
 */
class SceneMainToolBar {
    private final SceneMain sceneMain;
    private final ToolBar toolBar;
    Button btnAddFile;
    Button btnPreview;

    Button btnZoomIn;
    Button btnZoomReset;
    Button btnZoomOut;

    Button btnLayerOptions;
    Button btnExport;
    Button btnOpenResultDir;

    private File targetDir;
    private static final String NO_FILE_BASE64 = "data:image/xml;base64," +
            "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2Zy" +
            "BQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZ" +
            "HRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiCiAgICAg" +
            "d2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4IiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNTE" +
            "yIDUxMiIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+Cjx0ZXh0IHRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIDEgMTE3Ljg2MDQgMTI5LjE4NikiPj" +
            "x0c3BhbiB4PSIwIiB5PSIwIiBmb250LWZhbWlseT0iJ0Fkb2JlU29uZ1N0ZC1MaWdodC1HQnBjLUVVQy1IJyIgZm9udC1zaXplPSIyNCI+6" +
            "K+36YCJ5oup5LiA5Liq5paH5Lu26aKE6KeIPC90c3Bhbj4KICAgIDx0c3BhbiB4PSIwIiB5PSI1Ny42IiBmb250LWZhbWlseT0iJ0Fkb2Jl" +
            "U29uZ1N0ZC1MaWdodC1HQnBjLUVVQy1IJyIKICAgICAgICAgICBmb250LXNpemU9IjI0Ij5QbGVhc2Ugc2VsZWN0IGEgZmlsZSB0byBwcmV" +
            "2aWV3PC90c3Bhbj48L3RleHQ+Cjwvc3ZnPgo=";

    private long lastMoveTime;
    private Point mousePoint;

    SceneMainToolBar(SceneMain sceneMain) {
        this.sceneMain = sceneMain;
        this.toolBar = sceneMain.toolBar;
        init();
    }

    private void init() {
        targetDir = new File(sceneMain.workDir, "svg");
        if (!targetDir.exists())
            targetDir.mkdirs();
        reset();

        ObservableList<Node> items = toolBar.getItems();

        btnAddFile = new Button(I18N.getString("toolbar.add"), makeImageView("cad.png"));
        btnPreview = new Button(I18N.getString("toolbar.preview"), makeImageView("preview.png"));
        btnAddFile.setOnAction(this::addFile);
        btnPreview.setOnAction(this::preview);

        btnZoomIn = new Button("", makeImageView("zoom_in.png"));
        btnZoomReset = new Button("", makeImageView("zoom_reset.png"));
        btnZoomOut = new Button("", makeImageView("zoom_out.png"));
        btnZoomIn.setOnAction(this::zoomIn);
        btnZoomReset.setOnAction(this::zoomReset);
        btnZoomOut.setOnAction(this::zoomOut);

        btnLayerOptions = new Button(I18N.getString("toolbar.options"), makeImageView("layers.png"));
        btnExport = new Button(I18N.getString("toolbar.export"), makeImageView("export.png"));
        btnOpenResultDir = new Button(I18N.getString("toolbar.openResultDir"), makeImageView("dir.png"));
        btnLayerOptions.setOnAction(this::showLayerOptions);
        btnOpenResultDir.setOnAction(this::openResultDir);
        btnExport.setOnAction(this::exportSvg);

        items.addAll(
                btnAddFile, btnPreview, btnZoomIn, btnZoomReset, btnZoomOut,
                btnLayerOptions, btnExport, btnOpenResultDir);
    }

    private void reset() {
        sceneMain.lblPreviewFileName.setText("");
        sceneMain.cadFiles.clear();
        sceneMain.cadFileList.getItems().clear();
        loadNoSvg();
    }

    private ImageView makeImageView(String name) {
        InputStream ins = Urls.getResourceAsStream("/jfx/images/" + name);
        return new ImageView(new Image(ins));
    }

    private void addFile(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().add(
                new FileChooser.ExtensionFilter("AutoCad Drawing", "*.dwg", "*.dxf"));
        fileChooser.setTitle(I18N.getString("choose.cad.title"));
        fileChooser.setInitialDirectory(sceneMain.workDir.getParentFile());
        List<File> files = fileChooser.showOpenMultipleDialog(sceneMain.jfxContext.getStage());
        if (files == null || files.isEmpty()) {
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText(I18N.getString("choose.nothing"));
            alert.show();
            return;
        }

        reset();
        sceneMain.cadFiles.addAll(files);
        for (File file : sceneMain.cadFiles) {
            sceneMain.cadFileList.getItems().add(file.getName());
        }
        if (files.size() == 1) {
            sceneMain.cadFileList.getSelectionModel().select(0);
        } else {
            sceneMain.lblStatus.setText("add " + files.size() + " files.");
        }
    }

    private List<String> getSelectedFiles() {
        MultipleSelectionModel<String> selectionModel = sceneMain.cadFileList.getSelectionModel();
        List<String> fileNames = new ArrayList<>();
        fileNames.addAll(selectionModel.getSelectedItems());
        return fileNames;
    }

    private List<Integer> getSelectedIndices() {
        MultipleSelectionModel<String> selectionModel = sceneMain.cadFileList.getSelectionModel();
        return selectionModel.getSelectedIndices();
    }

    private void preview(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().add(
                new FileChooser.ExtensionFilter("svg file", "*.svg"));
        fileChooser.setTitle(I18N.getString("choose.svg.title"));
        fileChooser.setInitialDirectory(targetDir);
        File svgFile = fileChooser.showOpenDialog(JfxApplication.getContext().getStage());
        if (svgFile == null || !svgFile.exists()) {
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText(I18N.getString("choose.nothing"));
            alert.show();
            return;
        }

        sceneMain.lblPreviewFileName.setText(svgFile.getName());
        loadSvg(svgFile);
    }


    private void loadSvg(File svgFile) {
        URL url = null;
        try {
            url = svgFile.toURI().toURL();
        } catch (MalformedURLException e) {
            e.printStackTrace();
            sceneMain.lblStatus.setText("Load svg error:" + e.getMessage());
        }
        if (url == null)
            return;

        sceneMain.lblStatus.setText("Load: " + svgFile.getAbsolutePath());
        sceneMain.pgBar.setProgress(0);
        if (sceneMain.jsvgScrollPane == null) {
            JSVGCanvas canvas = new JSVGCanvas();
            sceneMain.jsvgScrollPane = new JSVGScrollPane(canvas);
            sceneMain.jsvgScrollPane.setBackground(Color.GREEN);
            sceneMain.swingContainer.setContent(sceneMain.jsvgScrollPane);
            canvas.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {
                @Override
                public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
                    Platform.runLater(() -> {
                        sceneMain.lblStatus.setText("LoadingStarted");
                        sceneMain.pgBar.setProgress(10);
                    });
                }

                @Override
                public void documentLoadingCancelled(SVGDocumentLoaderEvent e) {
                    Platform.runLater(() -> {
                        sceneMain.lblStatus.setText("LoadingCancelled");
                    });
                }

                @Override
                public void documentLoadingFailed(SVGDocumentLoaderEvent e) {
                    Platform.runLater(() -> {
                        sceneMain.lblStatus.setText("LoadingFailed");
                    });
                }

                @Override
                public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
                    Platform.runLater(() -> {
                        sceneMain.lblStatus.setText("LoadingCompleted");
                        sceneMain.pgBar.setProgress(100);
                    });
                }
            });
        }
        JSVGCanvas canvas = sceneMain.jsvgScrollPane.getCanvas();
        canvas.loadSVGDocument(url.toExternalForm());
    }

    private void loadNoSvg() {
        if (sceneMain.jsvgScrollPane == null) {
            JSVGCanvas canvas = new JSVGCanvas();
            sceneMain.jsvgScrollPane = new JSVGScrollPane(canvas);
            sceneMain.jsvgScrollPane.setBackground(Color.GREEN);
            sceneMain.swingContainer.setContent(sceneMain.jsvgScrollPane);
        }
        sceneMain.jsvgScrollPane.getCanvas().loadSVGDocument(NO_FILE_BASE64);
    }

    private void doScale(double scale) {
        if (sceneMain.jsvgScrollPane == null)
            return;

        JSVGCanvas canvas = sceneMain.jsvgScrollPane.getCanvas();
        Dimension canvasSize = canvas.getSize();
        Dimension paneSize = sceneMain.jsvgScrollPane.getSize();
        AffineTransform rat = canvas.getRenderingTransform();
        if (scale <= 0 || scale == 1.0) {
            int x = canvasSize.width / 2;
            int y = canvasSize.height / 2;
            AffineTransform t = AffineTransform.getTranslateInstance((double) x, (double) y);
            t.translate(-x, -y);
            canvas.setRenderingTransform(t);
            return;
        }

        AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
        int x = Math.min(canvasSize.width, paneSize.width) / 2;
        int y = Math.min(canvasSize.height, paneSize.height) / 2;
        AffineTransform t = AffineTransform.getTranslateInstance((double) x, (double) y);
        t.concatenate(at);
        t.translate(-x, -y);
        t.concatenate(rat);
        canvas.setRenderingTransform(t);
    }

    private void zoomIn(ActionEvent event) {
        doScale(1.25);
    }

    private void zoomReset(ActionEvent event) {
        doScale(1.0);
    }

    private void zoomOut(ActionEvent event) {
        doScale(0.8);
    }

    private void exportSvg(ActionEvent event) {
        System.out.println("export");
        if (sceneMain.cadFiles.isEmpty()) {
            return;
        }

        int success = 0;
        for (File file : sceneMain.cadFiles) {
            sceneMain.lblStatus.setText("正在导出：" + file.getName());
            CadImageExporter exporter = new CadImageExporter(file, targetDir);
            try {
                exporter.exportToSvg(ExportOptions.getInstance());
                success++;
                sceneMain.lblStatus.setText("导出：" + file.getName() + "成功。");
            } catch (IOException e) {
                e.printStackTrace();
                sceneMain.lblStatus.setText("导出：" + file.getName() + "时发生错误！");
            }
        }
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText("成功导出了：" + success + " 个cad文件！");
        alert.show();
    }

    private void showLayerOptions(ActionEvent event) {
        FxmlLoaderBuilder builder = FxmlLoaderBuilder.make("/jfx/LayerOptions.fxml", JfxApplication.getContext());
        JfxDialog dialog = new JfxDialog();
        dialog.setTitle(I18N.getString("options.title"));
        DialogPane pane = new DialogPane();
        pane.setContent(builder.load());
        dialog.setDialogPane(pane);
        ButtonType okType = new ButtonType(I18N.getString("options.ok"), ButtonBar.ButtonData.OK_DONE);
        ButtonType closeType = new ButtonType(I18N.getString("options.close"), ButtonBar.ButtonData.CANCEL_CLOSE);
        dialog.getDialogPane().getButtonTypes().addAll(okType, closeType);
        Optional<ButtonType> buttonType = dialog.showAndWait();
        if (buttonType.get() == okType) {
            LayerOptions layerOptions = builder.getController();
            layerOptions.updateOptions();
            System.out.println(ExportOptions.getInstance());
        }
    }

    private void openResultDir(ActionEvent event) {
        try {
            Desktop.getDesktop().browse(targetDir.toURI());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
